<template>
  <el-dialog v-model="dialogVisible" :title="parameter.title" width="680px" lock-scroll destroy-on-close draggable>
    <el-form ref="formRef" :model="parameter.form" :rules="rules" label-width="100px" label-suffix=" :">
      <el-form-item label="模板下载">
        <el-button type="primary" :icon="Download" @click="downloadTemp"> 点击下载 </el-button>
      </el-form-item>
      <el-form-item label="所属机构" prop="orgId">
        <el-cascader
          v-model="parameter.form.orgId"
          :options="formInline.orgOptions"
          :props="{ checkStrictly: true, emitPath: false }"
          style="width: 100%"
          clearable
          filterable
          placeholder="请选择上级目录"
        >
          <template #default="{ node, data }">
            <span>{{ data.label }}</span>
            <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
          </template>
        </el-cascader>
      </el-form-item>
      <el-form-item label="角色集合" prop="roleIds">
        <el-select v-model="parameter.form.roleIds" placeholder="请分配用户角色" multiple clearable>
          <el-option v-for="item in formInline.roleOptions" :key="item.value" :label="item.label" :value="item.value" />
        </el-select>
      </el-form-item>
      <el-form-item label="文件上传" prop="file">
        <el-upload
          action="#"
          class="upload"
          :drag="true"
          :limit="excelLimit"
          :multiple="true"
          :show-file-list="true"
          :auto-upload="false"
          :on-change="beforeExcelUpload"
          :on-exceed="handleExceed"
          :on-remove="() => (parameter.form.file = null)"
          :accept="parameter.fileType!.join(',')"
        >
          <slot name="empty">
            <el-icon class="el-icon--upload">
              <upload-filled />
            </el-icon>
            <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
          </slot>
          <template #tip>
            <slot name="tip">
              <div class="el-upload__tip">请上传 .xls , .xlsx 标准格式文件，文件最大为 {{ parameter.fileSize }}M</div>
            </slot>
          </template>
        </el-upload>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import type { FormInstance, FormRules, UploadFile } from "element-plus";
import type { ResultData, Option } from "@/api/interface";
import { ref, reactive, watch } from "vue";
import { useDownload } from "@/hooks/useDownload";
import { ElMessage, ElNotification } from "element-plus";
import { getOrgCascaderOptionApi } from "@/api/modules/system/org";
import { getRoleOptionApi } from "@/api/modules/system/role";
import { Download } from "@element-plus/icons-vue";

defineOptions({
  name: "SystemUserImport"
});

/** 系统用户 */
interface EditProps {
  /** 标题 */
  title: string;
  /** 待提交的表单 */
  form: Partial<{
    orgId: string;
    roleIds: string[];
    file: File | null;
  }>;
  /** 上传文件的大小 */
  fileSize?: number;
  /** 上传文件的类型 */
  fileType?: File.ExcelMimeType[];
  /** 导入模版下载Api */
  tempApi?: (params: any) => Promise<any>;
  /** 上传文件的Api */
  importApi?: (params: any) => Promise<ResultData<boolean>>;
  /** 获取表格数据的Api */
  getTableList?: () => void;
}

/** 表单内联数据 */
interface FormInline {
  /** 机构选项 */
  orgOptions: Option.CascadeOption[];
  /** 角色选项 */
  roleOptions: Option.SelectOption[];
}

/** 模板编码 */
const templateCode: string = "T_Sys_User_Import";

/** 表单实例 */
const formRef = ref<FormInstance>();
/** dialog 状态 */
const dialogVisible = ref(false);
// 最大文件上传数
const excelLimit = ref(1);
/** 表单验证规则 */
const rules = reactive<FormRules>({
  orgId: [{ required: true, message: "请选择所属机构", trigger: "blur" }],
  roleIds: [{ required: true, message: "请选择角色", trigger: "blur" }],
  file: [{ required: true, message: "请选择待导入的 Excel", trigger: "blur" }]
});
/** 父组件传过来的参数 */
const parameter = ref<EditProps>({
  title: "",
  form: {},
  fileSize: 5,
  fileType: ["application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]
});
/** 表单内联数据 */
const formInline = reactive<FormInline>({
  orgOptions: [],
  roleOptions: []
});

/**
 * 接收父组件参数
 *
 * @param params 父组件传过来的参数
 * @returns void
 */
const acceptParams = (params: EditProps) => {
  parameter.value = { ...parameter.value, ...params };
  dialogVisible.value = true;
};

/**
 * 初始化表单
 *
 * 1. 重置表单
 * 2. 获取机构和角色选项
 *
 * @returns void
 */
const initFormInline = () => {
  formRef.value?.resetFields();

  // 获取机构和角色选项
  Promise.all([getOrgCascaderOptionApi(), getRoleOptionApi()]).then(([org, role]) => {
    formInline.orgOptions = org.data;
    formInline.roleOptions = role.data;
  });
};

/**
 * Excel 导入模板下载
 *
 * @returns void
 */
const downloadTemp = () => {
  if (!parameter.value.tempApi) return;
  useDownload(parameter.value.tempApi, "", { code: templateCode });
};

/**
 * 文件上传之前判断
 *
 * @param file 上传的文件
 * @returns 是否可以上传
 */
const beforeExcelUpload = (file: UploadFile) => {
  const isExcel = parameter.value.fileType!.includes(file.raw?.type as File.ExcelMimeType);
  const fileSize = file.size! / 1024 / 1024 < parameter.value.fileSize!;
  if (!isExcel)
    ElNotification({
      title: "温馨提示",
      message: "上传文件只能是 xls / xlsx 格式！",
      type: "warning"
    });
  if (!fileSize)
    setTimeout(() => {
      ElNotification({
        title: "温馨提示",
        message: `上传文件大小不能超过 ${parameter.value.fileSize}MB！`,
        type: "warning"
      });
    }, 0);

  const result = isExcel && fileSize;
  if (result) {
    parameter.value.form.file = file.raw as File;
  } else {
    parameter.value.form.file = null;
  }

  return result;
};

// 文件数超出提示
const handleExceed = () => {
  ElNotification({
    title: "温馨提示",
    message: "最多只能上传一个文件！",
    type: "warning"
  });
};

/**
 * 提交表单
 *
 * 1. 校验表单
 * 2. 表单数据处理
 * 3. 提交表单
 * 4. 提交结果处理
 * 5. 异常处理
 *
 * @returns void
 */
const handleSubmit = () => {
  formRef.value
    // 1. 校验表单
    ?.validate()
    // 2. 表单数据处理
    .then(() => {
      let excelFormData = new FormData();
      excelFormData.append("orgId", parameter.value.form.orgId!);
      excelFormData.append("roleIds", parameter.value.form.roleIds!.join(","));
      excelFormData.append("file", parameter.value.form.file!);

      return excelFormData;
    })
    // 3. 提交表单
    .then(form => {
      return parameter.value.importApi!(form);
    })
    // 4. 提交结果处理
    .then(({ data }) => {
      if (data) {
        ElMessage.success({ message: `${parameter.value.title}成功！` });
        parameter.value.getTableList!();
        dialogVisible.value = false;
      } else {
        ElMessage.error({ message: `${parameter.value.title}失败！` });
      }
    })
    // 5. 异常处理
    .catch((error: Error) => {
      if (error.message) ElMessage.error({ message: `${parameter.value.title}异常：${error.message}` });
      else ElMessage.error({ message: "请检查表单数据是否填写完整！" });
    });
};

// 监听 dialogVisible 的变化
watch(dialogVisible, val => {
  if (val) {
    initFormInline();
  }
});

// 暴露给父组件的属性和方法
defineExpose({
  acceptParams
});
</script>

<style lang="scss" scoped>
.upload {
  width: 100%;
}
</style>
